#include <iostream>
using std::cout;
using std::endl;

class Data{
public:
    Data(){
        cout << "Data()" << endl;
    }

    Data(int x)
    : _data(x)
    { cout << "Data(int)" << endl; }

    int getData() const{
        return _data;
    }

    ~Data(){
        cout << "~Data()" << endl;
    }
private:
    int _data = 10;
};


class MiddleLayer{
public:
    MiddleLayer(Data * p)
    : _pdata(p)
    {
        cout << "MiddleLayer(Data*)" << endl; 
    }

    Data* operator->(){
        return _pdata;
    }

    Data & operator*(){
        return *_pdata;
    }

    ~MiddleLayer(){
        cout << "~MiddleLayer()" << endl;
        if(_pdata){
            delete _pdata;
            _pdata = nullptr;
        }
    }
    friend class ThirdLayer;
private:
    Data * _pdata;
};

class ThirdLayer{
public:
    ThirdLayer(MiddleLayer * pml)
    : _ml(pml)
    { cout <<"ThirdLayer(MiddleLayer*)" << endl; }

    ~ThirdLayer(){
        cout << "~ThirdLayer()" << endl;
        if(_ml){
            delete _ml;
            _ml = nullptr;
        }
    }

    MiddleLayer& operator->(){
        return *_ml;
    }

    //(1)一级一级进行关联
    /* MiddleLayer & operator*(){ */
    /*     return *_ml; */
    /* } */

    Data & operator*(){
        return *((*_ml)._pdata);
    }
private:
    MiddleLayer * _ml;
};

void test1(){
    ThirdLayer tl(new MiddleLayer(new Data));
    cout << tl->getData() << endl;
    //前面这个括号里面的内容是tl对象调用自己的箭头运算符重载函数
    //返回值是一个MiddleLayer对象
    //MiddleLayer对象之所以可以直接使用箭头运算符调用getData函数
    //是因为MiddleLayer类中对箭头运算符进行过重载
    cout << (tl.operator->())->getData() << endl;
    //本质
    cout << ((tl.operator->()).operator->())->getData() << endl;

    //(1)一级一级进行关联
    /* (*(*tl)).getData(); */
    cout << (*tl).getData() << endl;
    (tl.operator*()).getData();//本质
}

void test0(){
    //Data * p = new Data
    //MiddleLayer ml(p)
    MiddleLayer ml(new Data);
    cout << ml->getData() << endl;
    cout << (ml.operator->())->getData() << endl;//本质

    cout << (*ml).getData() << endl;
    cout << (ml.operator*()).getData() << endl;//本质

    Data * p = new Data();
    p->getData();
    (*p).getData();
    delete p;
    p = nullptr;
}

int main(void){
    test1();
    return 0;
}
